/*
 * This file is part of the VanitySearch distribution (https://github.com/JeanLucPons/VanitySearch).
 * Copyright (c) 2019 Jean Luc PONS.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "GPUEngine.h"
#include <math.h>

using namespace std;


void GPUEngine::GenerateCode(Secp256K1 *secp, int size) {

  // Compute generator table
  Point *Gn = new Point[size];
  Point g = secp->G;
  Gn[0] = g;
  g = secp->DoubleDirect(g);
  Gn[1] = g;
  for (int i = 2; i < size; i++) {
    g = secp->AddDirect(g, secp->G);
    Gn[i] = g;
  }
  // _2Gn = CPU_GRP_SIZE*G
  Point _2Gn = secp->DoubleDirect(Gn[size / 2 - 1]);

  // Write file
  FILE *f = fopen("GPU/GPUGroup.h", "w");

  fprintf(f, "// File generated by GPUEngine::GenerateCode()\n");
  fprintf(f, "// GROUP definitions\n");
  fprintf(f, "#define GRP_SIZE %d\n\n", size);
  fprintf(f, "// _2Gn = GRP_SIZE*G\n");
  fprintf(f, "__device__ __constant__ uint64_t _2Gnx[4] = %s;\n", _2Gn.x.GetC64Str(4).c_str());
  fprintf(f, "__device__ __constant__ uint64_t _2Gny[4] = %s;\n\n", _2Gn.y.GetC64Str(4).c_str());
  fprintf(f, "// SecpK1 Generator table (Contains G,2G,3G,...,(GRP_SIZE/2 )G)\n");
  fprintf(f, "__device__ __constant__ uint64_t Gx[][4] = {\n");
  for (int i = 0; i < size/2; i++) {
    fprintf(f, "  %s,\n", Gn[i].x.GetC64Str(4).c_str());
  }
  fprintf(f, "};\n");

  fprintf(f, "__device__ __constant__ uint64_t Gy[][4] = {\n");
  for (int i = 0; i < size/2; i++) {
    fprintf(f, "  %s,\n", Gn[i].y.GetC64Str(4).c_str());
  }
  fprintf(f, "};\n\n");

  fclose(f);
  delete[] Gn;

}
